package com.xsf.jieyou.business.controller;

import com.google.common.collect.Maps;
import com.xsf.jieyou.business.BusinessException;
import com.xsf.jieyou.business.common.dto.ResponseResult;
import com.xsf.jieyou.business.common.dto.ResponseStatus;
import com.xsf.jieyou.business.dto.LoginParam;
import com.xsf.jieyou.business.dto.WeChatParam;
import com.xsf.jieyou.business.service.LoginServiceImpl;
import com.xsf.jieyou.cloud.api.CloudRedisQrcodeService;
import com.xsf.jieyou.commons.utils.IDUtils;
import com.xsf.jieyou.commons.utils.IdWorkerUtils;
import com.xsf.jieyou.commons.utils.QRCodeUtils;
import com.xsf.jieyou.provider.api.ProviderTbUserRoleService;
import com.xsf.jieyou.provider.api.ProviderTbUserService;
import com.xsf.jieyou.provider.domain.TbUser;
import com.xsf.jieyou.provider.domain.TbUserRole;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码登录  控制层
 *
 * @author xsfno1
 * @version v1.0.0
 * @date 2020/3/10 23:42
 * @see com.xsf.jieyou.business.controller
 **/
@RestController
@RequestMapping(value = "/user/qrcode")
@RefreshScope
public class  QrCodeController {
    @Resource
    private LoginServiceImpl loginServiceImpl;
    @Reference(version = "1.0.0")
    private ProviderTbUserService providerTbUserService;
    @Reference(version = "1.0.0")
    private ProviderTbUserRoleService providerTbUserRoleService;
    /**
     * 二维码基本地址
     */
    @Value("${qrcode.url}")
    private String qrcodeUrl;
    @Resource
    private QRCodeUtils qrCodeUtils;
    @Resource
    private IdWorkerUtils idWorkerUtils;
    @Reference(version = "1.0.0")
    private CloudRedisQrcodeService cloudRedisQrcodeService;

    /**
     * 扫描二维码
     *
     * @param code {@link String} 二维码唯一标识
     */
    @GetMapping("scan")
    public ResponseResult scanQrCode(String code) {
        // 1.获取二维码状态,判断二维码是否失效
        this.verifyQrcode(code);
        // 2.改变Redis状态 , -1 授权失败 0 未扫描 1 扫描成功 2 授权成功  null 过期
        this.cloudRedisQrcodeService.insertRedisQrCode(code, "1");
        return new ResponseResult<>(ResponseStatus.SUCCESS);
    }

    /**
     * 获取二维码
     */
    @GetMapping("")
    public ResponseResult getQrCode() throws IOException {
        // 1.创建图片
        // 获取唯一标识
        String code = this.idWorkerUtils.nextId() + "";
        String content = this.qrcodeUrl + code;
        // 获取二维码图片
        String qrCode = this.qrCodeUtils.crateQRCode(content);
        // 2.存入唯一标识code到Redis , -1 授权失败 0 未扫描 1 扫描成功 2 授权成功  null 过期
        this.cloudRedisQrcodeService.insertRedisQrCode(code, "0");

        // 3.封装返回值
        Map<String, Object> map = Maps.newHashMap();
        map.put("code", code);
        map.put("content", qrCode);

        System.out.println("code:" + code);
        System.out.println("content:" + qrCode);

        return new ResponseResult<>(ResponseStatus.SUCCESS, map);
    }

    /**
     * 检查二维码：登录页面轮询调用此方法，根据唯一标识code判断用户登录情况
     * -1 授权失败 0 未扫描 1 扫描成功 2 授权成功  null 过期
     *
     * @param code {@link String} 二维码唯一标识
     */
    @GetMapping("check/{code}")
    public ResponseResult checkQrCode(@PathVariable String code) {
        // 1.获取二维码状态
        String state = this.cloudRedisQrcodeService.selectRedisQrCode(code);
        // 注意:2授权  格式是 2#Username
        if (!StringUtils.isEmpty(state) && state.startsWith("2")) {
            state = "2";
        }
        Map<String, String> map = new HashMap<>(5);
        map.put("-1", "登录失败，您已取消授权");
        map.put("0", "等待扫描");
        map.put("1", "扫描成功，请授权登录");
        map.put("2", "授权成功，正在登录");
        map.put(null, "二维码已过期");

        // 封装返回结果
        Map<String, String> result = new HashMap<>(2);
        result.put("code", state);
        result.put("msg", map.get(state));

        return "1".equals(state) || "2".equals(state) ?
                new ResponseResult<>(ResponseStatus.SUCCESS, result) :
                new ResponseResult<>(ResponseStatus.DEFEATED, result);
    }

    /**
     * 授权
     *
     * @param code        {@link String} 二维码唯一标识
     * @param isAuthor    {@link Boolean} 是否授权,0 授权失败 1 授权成功
     * @param weChatParam {@link Boolean} 微信小程序-用户信息
     */
    @PostMapping("/author/{code}/{isAuthor}")
    public ResponseResult authorization(@PathVariable String code,
                                        @PathVariable Boolean isAuthor,
                                        @RequestBody WeChatParam weChatParam) {
        // 1.获取二维码状态,判断二维码是否失效
        this.verifyQrcode(code);
        // 2.修改二维码状态
        // 二维码状态: -1 授权失败 0 未扫描 1 扫描成功 2 授权成功  null 过期
        String state = isAuthor ? "2#" + weChatParam.getNickName() : "-1";
        this.cloudRedisQrcodeService.insertRedisQrCode(code, state);

        // ##########################################
        // 0,已授权
        System.out.println(weChatParam);
        if (isAuthor) {
            // -1,检查数据库是否存在该账号,无=>插入,[WeChatParam]微信小程序端传递的用户参数类
            int count = this.providerTbUserService.validateUsername(weChatParam.getNickName());
            // -2,不存在,插入
            if (count == 0) {
                // 封装TbUser
                TbUser tbUser = new TbUser();
                Long uid = IDUtils.getId();
                tbUser.setId(uid);
                tbUser.setNickName(weChatParam.getNickName());
                tbUser.setUsername(weChatParam.getNickName());
                tbUser.setIcon(weChatParam.getAvatarUrl());
                tbUser.setStatus(1);
                tbUser.setCreateTime(new Date());
                tbUser.setUpdated(new Date());
                // 1.添加用户
                this.providerTbUserService.insert(tbUser);
                // 2.添加角色
                TbUserRole tbUserRole = new TbUserRole();
                tbUserRole.setUserId(uid);
                // RoleId3=>普通用户
                tbUserRole.setRoleId(3L);
                this.providerTbUserRoleService.insertTbUserRole(tbUserRole);
            }
        }
        // ##########################################
        return new ResponseResult<>(ResponseStatus.SUCCESS);
    }

    /**
     * 登录
     *
     * @param code {@link String} 二维码唯一标识
     */
    @PostMapping("/login/{code}")
    public ResponseResult login(@PathVariable String code) {
        // 1.获取二维码状态,判断二维码已授权
        String state = this.cloudRedisQrcodeService.selectRedisQrCode(code);
        // 失效
        if (StringUtils.isEmpty(state)) {
            throw new BusinessException(ResponseStatus.DEFEATED, "二维码已失效");
        }
        // 判断是否已授权 2:已授权
        if (!state.startsWith("2")) {
            throw new BusinessException(ResponseStatus.DEFEATED, "未授权");
        }
        // 2.登录,执行无密码方式oAuth2安全认证
        // 注意:2授权  格式2#username
        String username = state.split("2#")[1];
        //2.1.查询用户对象
        TbUser tbUser = this.providerTbUserService.get(username);
        //2.2.oAuth2安全认证
        if (tbUser != null) {
            //无密码登录方式,通过设置默认密码"12345678"完成登录认证
            return this.loginServiceImpl.login(new LoginParam("#" + tbUser.getUsername(), "12345678"));
        }
        return new ResponseResult<>(ResponseStatus.DEFEATED);
    }

    /**
     * 校验二维码是否失效 , 失效=>抛出异常
     *
     * @param code {@link String} 二维码唯一标识
     */
    private void verifyQrcode(String code) {
        String state = this.cloudRedisQrcodeService.selectRedisQrCode(code);
        // 失效
        if (StringUtils.isEmpty(state)) {
            throw new BusinessException(ResponseStatus.DEFEATED, "二维码已失效");
        }
    }
}
